#include<unistd.h>
#include<iostream>
#include<functional>
#include<vector>
#include<memory>
#include<unordered_map>
#include<cstdint>

using TaskFunc  = std::function<void()>;//计数为0时执行计时任务
using ReleaseFunc = std::function<void()>;
class TimerTask
{
private:
    uint64_t _id;
    uint32_t _timeout;
    TaskFunc _task_cb;
    bool _canceled;
    ReleaseFunc _release;//用于删除TimerWheel中保存的定时器对象信息
public:
    TimerTask(uint64_t id,uint32_t timeout,TaskFunc task):_id(id),_timeout(timeout),_task_cb(task),_canceled(false)
    {}
    ~TimerTask(){
        if(_canceled==false)_task_cb();
        _release();
    }
    void setRelease(const ReleaseFunc&cb){
        _release = cb;
    }
    uint32_t delayTime(){
        return _timeout;
    }
    void Cancel(){
        _canceled = true;
    }
};

class TimerWheel{
    using PtrTask = std::shared_ptr<TimerTask>;
    using WeakTask = std::weak_ptr<TimerTask>;
    uint32_t _capacity;//容量，就是时间轮最大时长
    int _tick;//指针
    std::vector<std::vector<PtrTask>> _wheel;
    std::unordered_map<uint64_t, WeakTask> _timers;
private:
    void RomoveTimer(uint64_t id){
        auto it = _timers.find(id);
        if(it!=_timers.end()){
            _timers.erase(it);
        }
    }
public:
    TimerWheel():_capacity(60), _tick(0), _wheel(_capacity) {}
    void TimerAdd(uint64_t id,uint32_t timeout,const TaskFunc& task){
        //PtrTask p = std::make_shared<Timer_Task>(id, timeout, task);//使用参数构造
        PtrTask p = PtrTask(new TimerTask(id, timeout, task));//直接拷贝构造
        WeakTask p1 = WeakTask(p);//直接使用指针构造
        p->setRelease(std::bind(&TimerWheel::RomoveTimer, this, id));//将删除函数绑定给timertask
        int pos = (_tick + timeout) % _capacity;// timeout决定下标  //id是索引定时任务
        _timers[id] = p1;
        _wheel[pos].push_back(p);
    }
    void TimerRefresh(uint64_t id){
        auto it = _timers.find(id);
        if(it==_timers.end()){
            //没找到定时任务
            //不能增添新的，因为没有其他参数
            return;
        }
        PtrTask p = it->second.lock();//lock获取weak_ptr管理的对象对应的shared_ptr
        uint32_t delay = p->delayTime();//这个触发时间是固定时间
        int pos = (_tick + delay)%_capacity;//计算新的触发时间
        _wheel[pos].push_back(p);
    }
    void Cancel(uint64_t id){
        auto it = _timers.find(id);
        if(it==_timers.end()){
            return;
        }
        PtrTask p = it->second.lock();
        if(p)p->Cancel();
    }
    //这个函数应该每秒钟被执行一次，相当于秒针向后走了一步
    void RunTimerTask(){
        _tick = (_tick + 1)%_capacity;
        _wheel[_tick].clear();
    }
};

class Test {
    public:
        Test() {std::cout << "构造" << std::endl;}
        ~Test() {std::cout << "析构" << std::endl;}
};

void DelTest(Test *t) {
    delete t;
}

int main()
{
    TimerWheel tw;

    Test *t = new Test();

    tw.TimerAdd(888, 5, std::bind(DelTest, t));

    for(int i = 0; i < 5; i++) {
        sleep(1);
        tw.TimerRefresh(888);//刷新定时任务
        tw.RunTimerTask();//向后移动秒针
        std::cout << "刷新了一下定时任务，重新需要5s后才会销毁\n";
    }
    tw.Cancel(888);
    while(1) {
        sleep(1);
        std::cout << "-------------------\n";
        tw.RunTimerTask();//向后移动秒针
    }
    return 0;
}